﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using CaiyinSoft.NetGather.Protocol;
using CaiyinSoft.NetGather.NetGatherUtility;
using CaiyinSoft.NetGather.NetGatherLib.Filter;
using CaiyinSoft.NetGather.NetGatherLib.Analyzer;
using CaiyinSoft.NetGather.NetGatherLib.Publisher;
using CaiyinSoft.NetGather.NetGatherLib.URLSource;
using CaiyinSoft.NetGather.NetGatherLib.Filter.Process;
using CaiyinSoft.NetGather.NetGatherLib.Filter.Special;
using CaiyinSoft.NetGather.NetGatherLib.Filter.Generate;

namespace CaiyinSoft.NetGather.NetGatherLib
{
    [Serializable]
    public class Task:ISerializable,IDeserializationCallback
    {

        public static string Extension = ".tsk";
        static int Version = 2;

        public string TaskName { get; set; }
        public string TaskID { get; set; }
        public IURLSource URLSource { get; set; }
        public URLConverter Converter { get; set; }
        public IHTMLPublisher HTMLPubliser { get; set; }

        public int TestType { get; set; }
        public string TestURL { get; set; }
        public string TestHTML { get; set; }

        [NonSerialized]
        private bool StopFlag = false;
        public Task()
        {
            HTMLAnalyzerBase analyzer = new HTMLAnalyzerBase();
            TextURLSource source = new TextURLSource();
            SQLHTMLPublisher publisher = new SQLHTMLPublisher();
            URLConverter convert = new CaiyinSoft.NetGather.NetGatherLib.URLConverter();


            convert.Encoding = "UTF-8";
            convert.Interval = 10;
            convert.HTMLAnalyzer = analyzer;

            this.TaskName = "新任务";
            this.Converter = convert;
            this.URLSource = source;
            this.HTMLPubliser = publisher;

            convert.BeforePageGatherHandler += new EventHandler<PageGatherEventAgr>(convert_BeforePageGatherHandler);

        }

        public Task(SerializationInfo info, StreamingContext context)
        {
            int version = info.GetInt32("Version");
            TaskID = info.GetString("TaskID");
            TaskName = info.GetString("TaskName");
            URLSource = (IURLSource)info.GetValue("Source", typeof(IURLSource));
            Converter = (URLConverter)info.GetValue("Converter", typeof(URLConverter));
            HTMLPubliser = (IHTMLPublisher)info.GetValue("Publiser", typeof(IHTMLPublisher));

            TestType = 0;
            TestURL = "";
            TestHTML ="";
            if (version > 1)
            {
                TestType = info.GetInt32("TestType");
                TestURL = info.GetString("TestURL");
                TestHTML = info.GetString("TestHTML");
            }

            Converter.BeforePageGatherHandler += new EventHandler<PageGatherEventAgr>(convert_BeforePageGatherHandler);
        }

        void convert_BeforePageGatherHandler(object sender, PageGatherEventAgr e)
        {
            e.Cancel = StopFlag;
            if (BeforePageGatherHandler != null)
                BeforePageGatherHandler(this, e);
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            Converter.BeforePageGatherHandler -= new EventHandler<PageGatherEventAgr>(convert_BeforePageGatherHandler);
            info.AddValue("Version", Version);
            info.AddValue("TaskID", TaskID);
            info.AddValue("TaskName", TaskName);
            info.AddValue("Source", URLSource);
            info.AddValue("Converter", Converter);
            info.AddValue("Publiser", HTMLPubliser);
            info.AddValue("TestType", TestType);
            info.AddValue("TestURL", TestURL);
            info.AddValue("TestHTML", TestHTML);
        }

        public void OnDeserialization(object sender)
        { 
        }


        public void Start()
        {
            StopFlag = false;
            if (TaskStartHandler != null)
                TaskStartHandler(this, EventArgs.Empty);

            List<URLItem> URLItems= this.URLSource.GetURLCollection();
            for (int i = 0; i < URLItems.Count; i++)
            {
                var item = URLItems[i];
                item.Status = URLItemStatus.Running;
                setURLItemStatus(item);

                this.Converter.ReInit();
                this.Converter.SetInputURL(item.URL);
                Dictionary<int, string> htmls = null;

                try
                {
                    if (Converter.ListResult)
                    {
                        int pageIndex = 0;
                        while (true)
                        {
                            htmls = Converter.GetSingleInputHTMLDic(pageIndex++);
                            if (htmls == null || htmls.Count == 0)
                            {
                                break;
                            }
                            else
                            {
                                item.Status = URLItemStatus.Publicing;
                                setURLItemStatus(item);
                                this.HTMLPubliser.PublishListData(htmls, this.Converter.HTMLAnalyzer);
                            }
                        }
                    }
                    else
                    {
                        htmls = Converter.GetInputHTMLDic();
                        if (htmls != null && htmls.Count > 0)
                        {
                            item.Status = URLItemStatus.Publicing;
                            setURLItemStatus(item);
                            this.HTMLPubliser.Publish(htmls, this.Converter.HTMLAnalyzer);
                        }
                        else
                        {
                            break;
                        }
                    }
                    if (StopFlag == false)
                    {
                        item.Status = URLItemStatus.Finished;
                        setURLItemStatus(item);
                    }
                    else
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    item.Status = URLItemStatus.Error;
                    setURLItemStatus(item);

                    writeError(item.URL,ex);

                }

            }

            if (TaskStopHandler != null)
                TaskStopHandler(this, EventArgs.Empty);

        }

        private void writeError(string url,Exception ex)
        {
            string savePath = System.IO.Path.Combine(Environment.CurrentDirectory, "error.txt");
            if (!File.Exists(savePath))
            {
                File.Create(savePath).Close();
            }
            //File.Delete(SavePath);


            //StringBuilder sb = new StringBuilder();
            using (StreamWriter sw = new StreamWriter(savePath, true))
            {
                sw.WriteLine("==============================================================");
                sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") );
                sw.WriteLine(url);
                sw.Write(ex);
                sw.WriteLine("");
            }
        }
        private void setURLItemStatus(URLItem item)
        {
            this.URLSource.SetURLStatus(item, item.Status);
            if (TaskRunStatusHandler != null)
                TaskRunStatusHandler(this, new RunStatusEventAgr(item));
       
        }

        public void Stop()
        {
            StopFlag = true;
        }

        public static bool Save(string Path,Task task,bool newFile)
        {
            FileInfo fi = new FileInfo(Path);
            if (!Directory.Exists(fi.Directory.FullName))
            {
                Directory.CreateDirectory(fi.Directory.FullName);
            }

            if (File.Exists(Path) && newFile)
            {
                throw new Exception("文件已存在!");
            }

            string path1 = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "task.tsk");
            if (File.Exists(path1))
                File.Delete(path1);

            using (FileStream stream = new FileStream(path1, FileMode.CreateNew))
            {
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                formatter.Serialize(stream, task);
            }

            System.IO.File.Copy(path1, Path, true);
            return true;

        }

        public static Task Read(string Path)
        {
            if (!File.Exists(Path))
                return null;

            using (FileStream stream = new FileStream(Path, FileMode.Open))
            {
                if (stream.Length == 0)
                {
                    return null;
                }
                else
                {
                    try
                    {
                        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                        return formatter.Deserialize(stream) as Task;
                    }
                    catch
                    {
                        throw new FormatExpection();
                    }
                }
            }
        }


        public event EventHandler TaskStartHandler;
        public event EventHandler TaskStopHandler;
        public event EventHandler<PageGatherEventAgr> BeforePageGatherHandler;
        public event EventHandler<RunStatusEventAgr> TaskRunStatusHandler;

    }


    public class RunStatusEventAgr : EventArgs
    {
        public URLItem URLItem { get; private set; }
        public bool Cancel { get; set; }
        public RunStatusEventAgr(URLItem item)
        {
            this.URLItem = item;
            this.Cancel = false;
        }
    }

    public class FormatExpection : Exception
    {
        public override string Message
        {
            get
            {
                return "未知文件格式";
            }
        }
    }

}
